-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
toMatchObjectType + toExtend - replacements for toMatchTypeOf #126
base: main
Are you sure you want to change the base?
Conversation
toMatchObjectType + toExtend are my best friends now
commit: |
I see expectTypeOf<Pick<MyType, "a" | "b">>().toEqualTypeOf<{readonly a: string; b?: number}>() // fail Also not sure if this was intended, because documentation says: "This is a strict check, but only on the subset of keys that are in both types." Or I missed something? |
Yep, optional properties are checked too. All the goodness from More examples below, all work as expected. I might see what some other people think of this change before adding a few more tests to make clearer what it does. type MyType = {readonly a: string; b: number; c: {some: {very: {complex: 'type'}}}; d?: boolean}
expectTypeOf<MyType>().toMatchObjectType<{a: string; b: number}>() // fails - forgot readonly
expectTypeOf<MyType>().toMatchObjectType<{readonly a: string; b?: number}>() // fails - b shouldn't be optional
expectTypeOf<MyType>().toMatchObjectType<{readonly a: string; d: boolean}>() // fails - d should be optional
expectTypeOf<MyType>().toMatchObjectType<{readonly a: string; b: number}>() // passes
expectTypeOf<MyType>().toMatchObjectType<{readonly a: string; d?: boolean}>() // passes
type BinaryOp = {
(a: number, b: number): number
(a: bigint, b: bigint): bigint
}
type Calculator = {add: BinaryOp; subtract: BinaryOp}
expectTypeOf<Calculator>().toMatchObjectType<{add: BinaryOp}>()
expectTypeOf<Calculator>().toMatchObjectType<{subtract: BinaryOp}>()
expectTypeOf<Calculator>().toMatchObjectType<{add: BinaryOp; subtract: BinaryOp}>()
expectTypeOf<Calculator>().toMatchObjectType<{add: {(a: number, b: number): number; (a: bigint, b: bigint): bigint}}>()
expectTypeOf<Calculator>().toMatchObjectType<{add: (a: number, b: number) => number}>() // fails - only one overload
expectTypeOf<Calculator>().toMatchObjectType<{add: (a: bigint, b: bigint) => bigint}>() // fails - only one overload (also, noticed you're working on something similar https://github.com/tstyche/tstyche - looks nice! have you had a similar decision to make there?) |
Ah.. There was a typo. Got it. As you noticed somewhere: it is hard to explain what 'match' means in type context. For me it feels like (Yes, I had |
@mmkal Can edit: nvm just saw that it can. |
Is |
Yes it's the same. toMatchTypeOf would be deprecated by this change |
ea9bb32
to
307bb91
Compare
1934786
to
5971398
Compare
5971398
to
1bbe4b0
Compare
Update - it's now a "deep" pick, to match jest's toMatchObject. That enables this kind of thing: const user = {
email: 'a@b.com',
name: 'John Doe',
address: {street: '123 2nd St', city: 'New York', zip: '10001', state: 'NY', country: 'USA'},
}
expectTypeOf(user).toMatchObjectType<{name: string; address: {city: string}}>() It also differentiates it vs a simple usage of |
expectTypeOf({a: 1, b: 2}).toMatchObjectType<{a: number}>() // prefer this | ||
``` | ||
|
||
`.toEqualTypeOf`, `.toMatchObjectType`, and `.toExtend` all fail on missing properties: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As well as missing optional properties? (No time to try out. Sorry.)
Also I was wondering, why you don’t use .not
in these examples? Because // @ts-expect-error
makes these assertions pass also with older versions of this library (playground).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As well as missing optional properties? (No time to try out. Sorry.)
toEqualTypeOf
and toMatchObjectType
fail on missing optional properties, but toExtend
doesn't. Added some docs + tests to cover this explicitly though.
why you don’t use .not in these examples
Just because these examples are essentially the docs and .not
hasn't been introduced yet. I'd be open to reordering stuff to put .not
higher up, you raise a good point - it's less prone to "wrong" errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, it was my stupid mistake. I just copied this code to TS Playground and tried to mess up something. All worked really really well (including .not
). Until.. I realised that this was because of // @ts-expect-error
..
Closes #55
Closes #10
(if merged, collecting feedback first)
This introduces two new methods to be used instead of the ever-controversial
toMatchTypeOf
.toExtend
- does whattoMatchTypeOf
used to docontinues to do - basically just checkActual extends Expected
toMatchObjectType
- does aPick<...>
of actual, so you can do precise checks on a subset of your type's keys:toMatchTypeOf
is deprecated but won't be removed in the foreseeable futureNote:
toMatchObjectType
only accepts plain object expectations - no unions, no tuples, no primitivesI suspect most instances of
.toMatchTypeOf
could be happily replaced by.toMatchObjectType
, and the word "object" being in the name makes it a bit clearer what's happening - and it is closer to a compile-time version of the jest.toMatchObject
method.In the remainder of cases, people can reach for
toExtend
- though this one should be more rarely used, becauseextends
is a fairly weak assertion (and, in fact, you can achieve something similar with{} as MyType satisfies {a: string}
, without using any library.